﻿
using System.Collections.Generic;

namespace Pretext.Parsers {
    public class Parser {

        public Parser() {
            Tokens = new List<Token>();
        }

        public Parser(IEnumerable<Token> tokens)
            : this() {

            Tokens.AddRange(tokens);

        }

        public List<Token> Tokens { get; private set; }
    
        public int CurrentPosition { get; protected set; }

        protected bool IsFirstToken {
            get {
                return CurrentPosition == 0;
            }
        }
        protected bool IsLastToken {
            get {
                return CurrentPosition == (Tokens.Count - 1);
            }
        }

        protected Token PreviousToken {
            get {
                if (!IsFirstToken) return Tokens[CurrentPosition - 1];
                return null;
            }
        }
        protected Token NextToken {
            get {
                if (IsLastToken) return null;
                return Tokens[CurrentPosition + 1];
            }
        }

        protected Token CurrentToken {
            get {
                return Tokens[CurrentPosition];
            }
        }

        protected bool SeekNextToken(TokenType type) {

            while ((CurrentPosition + 1) < Tokens.Count) {
                CurrentPosition++;
                if (Tokens[CurrentPosition].Is(type))
                    break;
            }

            return Tokens[CurrentPosition].Is(type);

        }

        public List<Token> GetArguments() {

            // move to the next start of arguments
            SeekNextToken(TokenType.OpeningArgumentBracket);

#if DEBUG
            if (!Tokens[CurrentPosition].Is(TokenType.OpeningArgumentBracket))
                throw new SyntaxException("Arguments are expected but missing.");
#endif

            List<Token> args = new List<Token>();

            // keep collecting arguments until we reach the argument closing bracket
            while (Tokens[CurrentPosition].Type != TokenType.ClosingArgumentBracket) {

                switch (Tokens[CurrentPosition].Type) {
                    case TokenType.String:
                    case TokenType.Symbol:

                        args.Add(Tokens[CurrentPosition]);

                        break;
                }

                // next token
                CurrentPosition++;
            }

            return args;

        }

        public List<Token> GetBlock() {
        
            // gets the next block 
            // i.e.  { ... }
            
            // It will return a list of tokens within the block

            // TODO: write tests

            // seek the next start of a block

            return null;
        
        }

        void CheckForAndParseWriteShortcutMethod() {

            /*
            *  Check for the write shortcut method
            */
            if (Tokens[CurrentPosition].Is(TokenType.Symbol, "="))
                if (!IsFirstToken)
                    if (PreviousToken.Is(TokenType.StartOfPretextBracket)) {

                        // remove the "=" symbol
                        Tokens.RemoveAt(CurrentPosition);

                        // insert the 'write' symbol
                        Tokens.Insert(CurrentPosition++, new Token(TokenType.Symbol, "write"));
                        Tokens.Insert(CurrentPosition++, new Token(TokenType.GeneralSyntaxGrammer, "("));

                        SeekNextToken(TokenType.EndOfPretextBracket);

                        Tokens.Insert(CurrentPosition, new Token(TokenType.GeneralSyntaxGrammer, ")"));

                    }

        }

        protected int IndexOfNextTokenByType(TokenType type) {

            int pos = CurrentPosition;

            while (pos < Tokens.Count) {
                if (Tokens[pos].Is(type))
                    return pos;
                pos++;
            }

            return -1;

        }

        public virtual void ParseAllTokens() {

            // parse each token
            while (CurrentPosition < Tokens.Count) {

                // call the childs method
                ParseToken();

                // next position
                CurrentPosition++;

            }

        }

        // for sub-classes
        protected virtual void ParseToken(){
            CheckForAndParseWriteShortcutMethod();
        }

    }
}